home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / program / libkb100.zip / LIBKB-1.00 / SRC / KBOS.C < prev    next >
C/C++ Source or Header  |  1996-07-23  |  11KB  |  516 lines

  1. /* kbos.c -- operating system and BIOS keyboard access
  2.  * Copyright (C) 1995, 1996 Markus F.X.J. Oberhumer
  3.  * For conditions of distribution and use, see copyright notice in kb.h 
  4.  */
  5.  
  6. #if defined(__EMX__)
  7. #  include <sys/emx.h>        /* must be first include file */
  8. #endif
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <time.h>
  13. #include <kb.h>
  14. #include "_kb.h"
  15. #if defined(__GO32__)
  16. #  include <gppconio.h>
  17. #  undef kbhit            /* want to be able to call kbhit from libc */
  18.    int kbhit(void);        /* djgpp v2 */
  19. #endif
  20.  
  21.  
  22. #if defined(KB_LOCK_ALL_START)
  23. KB_LOCK_ALL_START(_libkb_kbos)
  24. #endif
  25.  
  26.  
  27. /* this file contains lots of #if ... */
  28.  
  29.  
  30. /***********************************************************************
  31. // utility functions
  32. ************************************************************************/
  33.  
  34. #if defined(KB_INT86_REGS)
  35.  
  36. __inline__ void _kb_int86_regs_init(KB_INT86_REGS *regs)
  37. {
  38.     memset(regs,0,sizeof(KB_INT86_REGS));
  39. #if defined(__WATCOMC__)
  40.     regs->w.ds = FP_SEG(regs);
  41. #if defined(__386__) && !defined(__WINDOWS_386__)
  42.     regs->w.fs = regs->w.gs = FP_SEG(regs);
  43. #endif
  44. #endif
  45. }
  46.  
  47. __inline__ void _kb_int86_regs_init_ax(KB_INT86_REGS *regs, unsigned short ax)
  48. {
  49.     _kb_int86_regs_init(regs);
  50. #if defined(__WATCOMC__)
  51.     regs->w.ax = ax;
  52. #else
  53.     regs->x.ax = ax;
  54. #endif
  55. }
  56.  
  57. #endif /* KB_INT86_REGS */
  58.  
  59.  
  60. /* check if we are running in a Windows DOS box */
  61. int _kb_iswin(void)
  62. {
  63. #if !defined(KB_INT86_REGS)
  64.     return 0;
  65. #elif defined(__GO32__) && !defined(__DJGPP__)
  66.     /* go32 doesn't support INT 0x2f, AX=0x1600 */
  67.     return -1;
  68. #else
  69.     KB_INT86_REGS regs;
  70. # if defined(__EMX__)
  71.     if (_osmode != DOS_MODE)
  72.         return 0;
  73.     if ((_emx_env & 0x1000) == 0)        /* if RSX not found */
  74.         return 0;
  75.     if (!KB_USE_INT86())                /* _int86() not allowed */
  76.         return -1;            
  77. # endif
  78.     _kb_int86_regs_init_ax(®s,0x1600);
  79.     KB_INT86(0x2f,®s);
  80.     if (regs.h.al == 0 || regs.h.al == 1 || 
  81.         regs.h.al == 0x80 || regs.h.al == 0xff)
  82.         return 0;
  83.     /* return major-version in high byte, minor-version in low byte */
  84.     return (regs.h.al << 8) | regs.h.ah;
  85. #endif /* KB_INT86_REGS */
  86. }
  87.  
  88.  
  89. /* sleep for a very short time */
  90. __inline__ void _kb_usleep (unsigned long usec)
  91. {
  92.     if (usec < 1024)
  93.         return;
  94. #if defined(__KB_LINUX) || defined(__DJGPP__)
  95.     usleep(usec);
  96. #elif defined(__EMX__)
  97.     _sleep2(usec / 1000);
  98. #elif defined(__KB_MSDOS)
  99.     delay((int) (usec / 1000));
  100. #endif
  101. }
  102.  
  103.  
  104. /***********************************************************************
  105. // BIOS wrapper
  106. // some documentation can be found in djgpp2/src/libc/bios/
  107. ************************************************************************/
  108.  
  109. #if defined(__EMX__) || defined(__GO32__) || defined(__WATCOMC__)
  110.  
  111. static __inline__ int _my_bioskey(unsigned cmd)
  112. {
  113.     KB_INT86_REGS regs;
  114.  
  115. #if defined(__EMX__)
  116.     /* ((_emx_env & 0x0800) == 0) || "emx: -ac not enabled for _int86()" */
  117.     if (!KB_USE_INT86())
  118.         return 0;
  119. #endif /* __EMX__ */
  120.  
  121.     _kb_int86_regs_init(®s);
  122.     regs.h.ah = cmd;
  123.     KB_INT86(0x16,®s);
  124.  
  125. #if defined(__WATCOMC__)
  126. #  define x w            /* regs.x.AA -> regs.w.AA */
  127. #endif
  128.  
  129.     switch (cmd)
  130.     {
  131.     case KB_KEYBRD_READY:
  132.     case KB_NKEYBRD_READY:
  133.         if (regs.x.flags & 0x40)    /* zero flag set -> no key is waiting */
  134.             return 0;
  135.         else if (regs.x.ax == 0)
  136.             return -1;                /* Control-Break */
  137.         else
  138.             return regs.x.ax;
  139.     case KB_KEYBRD_SHIFTSTATUS:
  140.         return regs.h.al;
  141.     case KB_KEYBRD_READ:
  142.     case KB_NKEYBRD_READ:
  143.     case KB_NKEYBRD_SHIFTSTATUS:
  144.         return regs.x.ax;
  145.     }
  146.     return 0;
  147.  
  148. #if defined(__WATCOMC__)
  149. #  undef x
  150. #endif
  151. }
  152.  
  153. #define _KB_BIOSKEY(x)    _my_bioskey(x)
  154.  
  155. #endif
  156.  
  157.  
  158. #if defined(__KB_MSDOS)
  159. #  if defined(__BORLANDC__) || defined(__TURBOC__) || defined(__GO32__)
  160. #    ifndef _KB_BIOSKEY
  161. #      define _KB_BIOSKEY(x)    bioskey(x)
  162. #    endif
  163. #  endif
  164. #  if defined(_MSC_VER) || defined(__WATCOMC__)
  165. #    ifndef _KB_BIOSKEY
  166. #      define _KB_BIOSKEY(x)    _bios_keybrd(x)
  167. #    endif
  168. #  endif
  169. #endif
  170.  
  171.  
  172. /***********************************************************************
  173. // BIOS level - lowest and (hopefully) fastest access level
  174. // If not applicable, OS level is used
  175. ************************************************************************/
  176.  
  177. __inline__ int kb_bioskey(unsigned cmd)
  178. {
  179. #if defined(_KB_BIOSKEY)
  180.     return _KB_BIOSKEY(cmd);
  181. #else
  182.     return 0;
  183. #endif
  184. }
  185.  
  186.  
  187. int kb_bios_kbhit(void)
  188. {
  189.     if (_kb_mode)
  190.         return kb_kbhit();
  191.  
  192. #if !defined(_KB_BIOSKEY)
  193.     return kb_os_kbhit();
  194. #elif defined(__GO32__)
  195.     return kbhit();                /* this uses BIOS and is damned fast */
  196. #else
  197. # if defined(__EMX__)
  198.     if (!KB_USE_INT86())
  199.         return kb_os_kbhit();    /* _int86() not allowed */
  200. # endif
  201.     return (_KB_BIOSKEY(KB_NKEYBRD_READY) != 0);
  202. #endif
  203. }
  204.  
  205.  
  206. unsigned kb_bios_getkey(void)
  207. {
  208.     if (_kb_mode)
  209.         return kb_getkey();
  210.  
  211.     if (!kb_bios_kbhit())
  212.         return 0;
  213.  
  214. #if !defined(_KB_BIOSKEY)
  215.     return kb_os_getkey();
  216. #elif defined(__GO32__)
  217.     return getxkey();            /* this uses BIOS */
  218. #else
  219. # if defined(__EMX__)
  220.     if (!KB_USE_INT86())
  221.         return kb_os_getkey();    /* _int86() not allowed */
  222. # endif
  223.     return kb_bios_keycode(_KB_BIOSKEY(KB_NKEYBRD_READ));
  224. #endif
  225. }
  226.  
  227.  
  228.  
  229. /***********************************************************************
  230. // emx getch() wrapper
  231. // returns 0 if no key is available
  232. ************************************************************************/
  233.  
  234. #if defined(__EMX__)
  235.  
  236. static int _last_key = -1;
  237.  
  238. static __inline__ int _my_read_kbd(int eat)
  239. {
  240.     if (_last_key == -1)
  241.         _last_key = _read_kbd(0,0,0);        /* echo, wait, sig */
  242.     if (_last_key == -1)
  243.         return 0;                            /* no key available */
  244.     if (eat)
  245.     {
  246.         int k = _last_key;
  247.         _last_key = -1;
  248.         return k;
  249.     }
  250.     else
  251.         return 1;
  252. }
  253.  
  254. #define _my_kbhit()        _my_read_kbd(0)
  255. #define _my_getch()        _my_read_kbd(1)
  256.         
  257. #endif /* __EMX__ */
  258.  
  259.  
  260. /***********************************************************************
  261. // Linux getch() wrapper
  262. // returns 0 if no key is available
  263. //
  264. // adapted from code written by Tommy Frandsen and Harm Hanemaayer
  265. // see svgalib 1.2.x: src/vgamisc.c
  266. //
  267. // This code is slow and doesn't work very well because stdin
  268. // is only temporary changed for each attempt to read a key.
  269. // It works better if you use kb_os_waitkey().
  270. ************************************************************************/
  271.  
  272. #if defined(__KB_LINUX)
  273.  
  274. #include <stdio.h>
  275. #include <termios.h>
  276. #include <unistd.h>
  277. #include <fcntl.h>
  278. #include <sys/ioctl.h>
  279. #include <sys/time.h>
  280.  
  281. /* use a buffer for keys, this works better */
  282. static unsigned char _key_buffer[128];
  283. static const int _key_size = HIGH(_key_buffer);
  284. static int _key_index = 0;
  285.  
  286. /* read keyboard file, fill buffer */
  287. static __inline__ void _my_read_kbd(int fd)
  288. {
  289.     if (_key_index < _key_size)
  290.     {
  291.         int n = read(fd,&_key_buffer[_key_index],_key_size-_key_index);
  292.         if (n > 0)
  293.             _key_index += n;
  294.     }
  295. }
  296.  
  297. /* wait for a key, fill buffer */
  298. static __inline__ void _my_read_kbd_and_wait(int fd, unsigned long usec)
  299. {
  300.     struct timeval tv, *tvp;
  301.     fd_set fds;
  302.  
  303.     FD_ZERO(&fds);
  304.     FD_SET(fd, &fds);
  305.     if (usec == (unsigned long)-1)
  306.         tvp = NULL;                        /* wait forever */
  307.     else
  308.     {
  309.         tv.tv_sec  = usec / 1000000;
  310.         tv.tv_usec = usec % 1000000;
  311.         tvp = &tv;
  312.     }
  313.     if (select(fd + 1, &fds, NULL, NULL, tvp) > 0)
  314.         _my_read_kbd(fd);
  315. }
  316.  
  317. /* read keyboard, fill buffer */
  318. static __inline__ void _my_read_a_key(unsigned long wait)
  319. {
  320.     struct termio zap, original;
  321.     int fd = fileno(stdin);
  322.  
  323.     if (ioctl(fd, TCGETA, &original) != 0)    /* Get termio */
  324.         return;
  325.     zap = original;
  326.     zap.c_cc[VMIN] = 0;                        /* Modify termio  */
  327.     zap.c_cc[VTIME] = 0;
  328.     zap.c_lflag = 0;
  329.     if (ioctl(fd, TCSETA, &zap) != 0)        /* Set new termio */
  330.         return;
  331.     if (wait)
  332.         _my_read_kbd_and_wait(fd,wait);
  333.     else
  334.         _my_read_kbd(fd);
  335.     ioctl(fd, TCSETA, &original);            /* Restore termio */
  336. }
  337.  
  338. /* get a key from the keyboard buffer or read from file */
  339. static unsigned _my_get_key(int eat, unsigned long wait)
  340. {
  341.     unsigned k;
  342.  
  343.     if (_key_index <= 0)
  344.     {
  345.         _my_read_a_key(wait);
  346.         if (_key_index <= 0)
  347.             return 0;                    /* no key available */
  348.     }
  349.     k = _key_buffer[0];
  350.     if (eat)
  351.     {
  352.         _key_index--;
  353.         if (_key_index > 0)
  354.             memmove(&_key_buffer[0],&_key_buffer[1],_key_index);
  355.     }
  356.     return k;
  357. }
  358.  
  359. /* this is the 'public' entry point */
  360. static unsigned _linux_getkey(int eat, unsigned long wait)
  361. {
  362.     unsigned k = _my_get_key(eat,wait);
  363.  
  364. #if 0
  365.     /* TODO: convert Esc sequences to our portable keycode.
  366.      *       how can this be done i